<?php
/**
 *	KLF Framework
 *
 *	Written by Kristian Oye <kristianoye@gmail.com> on Oct 23, 2011
 *	Copyright (C) 2010-2011
 */
namespace KLF\System\Web
{
	use KLF\System\KComponent;
	use KLF\System\Data\KPreferenceMap;
	use KLF\System\Errors\KReadOnlyException;

	/**
	 *  Class KHttpRequest
	 *
	 *  @package KLF\System\Web
	 *  @access public
	 *  @author Kristian Oye <kristianoye@gmail.com>
	 *  @since 0.1
	 *  
	 *  @property array $AcceptedTypes Types accepted by client
	 *  @property string $ContentEncoding The content encoding.
	 *  @property int $ContentLength The length of the request data.
	 *  @property string $ContentType The MIME type of the request.
	 *  @property KHttpCookieCollection $Cookies The collection of cookies from the client.
	 *  @property array $Headers A collection of the request headers.
	 *  @property string $HttpMethod The method used to transport the request.
	 *  @property string $HostName The hostname of the request.
	 *  @property bool $IsAuthenticated Returns true if the user has been authenticated.
	 *  @property bool $IsSecureConnection Returns true if the connection is encrypted.
	 *  @property bool $IsLocal Returns true if the client is local to the server.
	 *  @property string $LocalPath 
	 *  @property array $Parameters The collection of parameters.
	 *  @property string $PhysicalPath The physical path on the server.
	 *  @property KHttpResponse $Respose The HTTP response object.
	 *  @property string $QueryString The query string.
	 *  @property string $RawUrl The raw URL.
	 *  @property string $RequestType The request type (POST, GET, etc)
	 *  @property KHttpResponse $Response The HTTP response object.
	 *  @property array $ServerVariables Variables from the server.
	 *  @property string $Url The URL requested by the client.
	 *  @property string $UserAgent The remote user-agent string.
	 *  @property string $UserHostAddress The remote client's address.
	 *  @property string $UserHostName The remote client's DNS name.
	 */
	class KHttpRequest extends KComponent implements \ArrayAccess
	{
		/**
		 * The current HTTP request.
		 * 
		 * @var KHttpRequest $_currentRequest
		 */
		private static $_currentRequest;
		
		/**
		 * The Accept-Charset request-header field can be used to indicate what character sets are acceptable for the response.
		 * This field allows clients capable of understanding more comprehensive or special- purpose character sets to signal 
		 * that capability to a server which is capable of representing documents in those character sets. 
		 * @var KPreferenceMap $_propAcceptCharacterSets
		 */
		protected $_propAcceptCharacterSets;
		
		/**
		 * The Accept-Language request-header field is similar to Accept, but restricts the set of natural languages
		 * that are preferred as a response to the request.
		 * 
		 * @var KPreferenceMap $_propAcceptTypes
		 */
		protected $_propAcceptLanguages;
		
		/**
		 * The MIME types accepted by the client.
		 * 
		 * @var KPreferenceMap $_propAcceptTypes
		 */
		protected $_propAcceptTypes;
		
		/**
		 * The MIME type of the request.
		 * 
		 * @var string $_propContentEncoding
		 */
		protected $_propContentEncoding = "";
		
		/**
		 * The Content-Length entity-header field indicates the size of the entity-body, in decimal number of OCTETs,
		 * sent to the recipient or, in the case of the HEAD method, the size of the entity-body that would have been
		 * sent had the request been a GET. 
		 * 
		 * @var integer $_propContentLength
		 */
		protected $_propContentLength;
		
		/**
		 * The Content-Encoding entity-header field is used as a modifier to the media-type&47; When present, its value
		 * indicates what additional content codings have been applied to the entity-body, and thus what decoding
		 * mechanisms must be applied in order to obtain the media-type referenced by the Content-Type header field.
		 * Content-Encoding is primarily used to allow a document to be compressed without losing the identity of its
		 * underlying media type.
		 * 
		 * @var string $_propContentType
		 */
		protected $_propContentType;
		
		/**
		 * The collection of cookies sent by the client.  To set a new cookie it must be added to the response.
		 * 
		 * @see KHttpResponse
		 * @var KHttpCookieCollection $_propCookies
		 */
		protected $_propCookies;
		
		/**
		 * The headers sent by the client during the request.
		 * 
		 * @var array $_propHeaders
		 */
		protected $_propHeaders;
		
		/**
		 * The transmission method used to send the request.
		 * 
		 * @var string $_propHttpMethod
		 */
		protected $_propHttpMethod;
		
		/**
		 * The host name the client is asking for.
		 * 
		 * @var string $_propHostName
		 */
		protected $_propHostName;
		
		/**
		 * 
		 * @var bool $_propIsAuthenticated
		 */
		protected $_propIsAuthenticated;
		
		/**
		 * 
		 * @var bool $_propIsSecureConnection
		 */
		protected $_propIsSecureConnection;
		
		/**
		 * 
		 * @var bool $_propIsLocal
		 */
		protected $_propIsLocal;
		
		/**
		 * 
		 * @var string $_propLocalPath
		 */
		protected $_propLocalPath;
		
		/**
		 * 
		 * @var array $_propParameters
		 */
		protected $_propParameters;
		
		/**
		 * 
		 * @var string $_propPhysicalPath
		 */
		protected $_propPhysicalPath;
		
		/**
		 * 
		 * @var KHttpResponse $_propResponse
		 */
		protected $_propResponse;
		
		/**
		 * 
		 * @var string $_propQueryString
		 */
		protected $_propQueryString;
		
		/**
		 * 
		 * @var string $_propRawUrl
		 */
		protected $_propRawUrl;
		
		/**
		 * 
		 * @var string $_propRequestType
		 */
		protected $_propRequestType;
		
		/**
		 * 
		 * @var array $_propServerVariables
		 */
		protected $_propServerVariables;
		
		/**
		 * 
		 * @var string $_propUrl
		 */
		protected $_propUrl;
		
		/**
		 * 
		 * @var unknown_type $_propUser
		 */
		protected $_propUser;
		
		/**
		 * 
		 * @var string $_propUserAgent
		 */
		protected $_propUserAgent;
		
		/**
		 * 
		 * @var string $_propUserHostAddress
		 */
		protected $_propUserHostAddress;
		
		/**
		 * 
		 * @var string $_propUserHostName
		 */
		protected $_propUserHostName;
		
		/**
		 * Creates an empty HTTP Request object.
		 */
		public function __construct()
		{
		}
		
		/**
		 * Returns information about the current request.
		 * 
		 * @return KHttpRequest
		 */
		public static function GetCurrentRequest()
		{
			if (!isset(self::$_currentRequest))
			{
				global $_SERVER;
				global $_COOKIE;
				global $_ENV;
				global $_SESSION;
			
				$req = new KHttpRequest();

				$req->_propAcceptCharacterSets = KHttpUtility::CreatePreferenceMap('AcceptedCharset', $_SERVER['HTTP_ACCEPT_CHARSET']);
				$req->_propAcceptLanguages = KHttpUtility::CreatePreferenceMap('AcceptedLanguage', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
				$req->_propAcceptTypes = KHttpUtility::CreatePreferenceMap('AcceptedTypes', $_SERVER['HTTP_ACCEPT']);
				
				$req->_propContentLength = 0;
				$req->_propContentType = "";
				$req->_propCookies = &$_COOKIE;
				$req->_propHeaders = apache_request_headers();
				$req->_propHttpMethod = $_SERVER['REQUEST_METHOD'];
				$req->_propHostName = $_SERVER["SERVER_NAME"];
				$req->_propIsAuthenticated = false;
				$req->_propIsSecureConnection = isset($_SERVER['HTTPS']);
				if (isset($_SERVER['REMOTE_ADDR']))
				{
					$req->_propIsLocal = ($_SERVER['REMOTE_ADDR'] === $_SERVER['SERVER_ADDR']) ||
									($_SERVER['REMOTE_ADDR'] === '127.0.0.1');
				}
				$req->_propParameters = array_merge(
					is_array($_SERVER) ? $_SERVER : array(),
					is_array($_REQUEST) ? $_REQUEST : array(),
					is_array($_ENV) ? $_ENV : array(),
					is_array($_SESSION) ? $_SESSION : array());
				$req->_propPhysicalPath = $_SERVER['DOCUMENT_ROOT'];
				$req->_propRawUrl = $_SERVER['REQUEST_URI'];
				$req->_propQueryString = $_SERVER['QUERY_STRING'];
				$req->_propRequestType = &$_SERVER['REQUEST_METHOD'];
				$req->_propServerVariables = &$_SERVER;
				$req->_propUrl = KUrl::GetCurrentUrl();
				$req->_propLocalPath = $req->Url->LocalPath;
				$req->_propUser = null;
				$req->_propUserAgent = $_SERVER["HTTP_USER_AGENT"];
				$req->_propUserHostAddress = $_SERVER['REMOTE_ADDR'];
				$req->_propUserHostName = gethostbyaddr($_SERVER['REMOTE_ADDR']);
				
				self::$_currentRequest = $req;
			}
			
			return self::$_currentRequest;
		}
		
		/**
		 * Returns a parameter from the request or a default valut.
		 * 
		 * @param mixed $vname
		 * @param mixed $defaultValue
		 */
		public function Param($vname, $defaultValue=NULL)
		{
			global $_REQUEST, $_COOKIE, $_SESSION;
			
			if (isset($_SESSION[$vname]))
			{
				return $_SESSION[$vname];
			}
			elseif (isset($_COOKIE[$vname]))
			{
				return $_REQUEST[$vname];
			}
			elseif (isset($_REQUEST[$vname]))
			{
				return $_REQUEST[$vname];
			}
			elseif (isset($_SERVER[$vname]))
			{
				return $_SERVER[$vname];
			}
			return $defaultValue;
		}
		
		/**
		 * Returns the object in string form.
		 * 
		 * @return string
		 */
		public function __toString()
		{
			return var_export($this, true);
		}
		
		/**
		 * Checks to see if a particular key exists.
		 * 
		 * @param string $offset
		 * @return bool
		 */
		public function offsetExists($offset)
		{
			$result = $this->Param($offset, NULL);
			return isset($result);
		}
		
		/**
		 * Allows array access into the request data collections.
		 * 
		 * @param string $offset
		 * @return Ambigous <unknown, mixed>|NULL
		 */
		public function offsetGet($offset)
		{
			return $this->Param($offset);
		}
		
		/**
		 * (non-PHPdoc)
		 * @see ArrayAccess::offsetSet()
		 * @throws KReadOnlyException
		 */
		public function offsetSet($offset, $value)
		{
			throw new KReadOnlyException('Collection', 'Request');
		}
		
		/**
		 * (non-PHPdoc)
		 * @see ArrayAccess::offsetUnset()
		 * @throws KReadOnlyException
		 */
		public function offsetUnset($offset)
		{
			throw new KReadOnlyException('Collection', 'Request');
		}
	}
}